/*
 * Copyright 2014, NuzoweR@Schneefeuer <nuzower@gmail.com>.
 * The Settlers Online - Combat Simulator (tsosim).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef UNITS_H_
#define UNITS_H_

#include <map>
#include <string>

struct Skill {
	enum ESkill     { NONE = 0, SPLASH_DAMAGE = 1, TOWER_BONUS = 2, ARMOR_PENETRATION = 4, /*BONUS_DAMAGE = 8,*/ ATTACK_WEAKEST = 16, WEAK = 32, GENERAL = 64 };
	int value;

	Skill() : value(NONE) {}

	bool   hasSkill(ESkill skill) const { return (value & skill) != 0;   }
	Skill& remove(ESkill skill)         { value ^= skill; return *this; }
	Skill& add(ESkill skill)            { value |= skill; return *this; }

	bool   add(std::string const& skill) {
		if     (skill == "WEAK")             { add(Skill::WEAK); return true; }
		else if(skill == "ATTACK_WEAKEST")   { add(Skill::ATTACK_WEAKEST); return true; }
		else if(skill == "SPLASH_DAMAGE")    { add(Skill::SPLASH_DAMAGE); return true; }
		else if(skill == "TOWER_BONUS")      { add(Skill::TOWER_BONUS); return true; }
		else if(skill == "ARMOR_PENETRATION"){ add(Skill::ARMOR_PENETRATION); return true; }
		else if(skill == "GENERAL")          { add(Skill::GENERAL); return true; }
		return false;
	}
};

struct Enemy {
	enum Type  { NONE = 0, REGULAR, BANDITS, TRAITORS, PIRATES, CULTISTS, RAIDERS, NORDS, KINGDOM, WILDLIFE, EPIC, EVENT };

	// type -> bonus damage (in percent)
	typedef std::map<Type,int> bonus_map_t;

	bonus_map_t bonus;

	Enemy() : bonus() {};

	Enemy& setBonus(Type t, int dmg) { bonus[t] = dmg; return *this; }
	int    getBonus(Type t) const    {
		bonus_map_t::const_iterator cit = bonus.find(t);
		return cit != bonus.end() ? cit->second : 0;
	}

	static Type toType(std::string const& type) {
		return 	type == "REGULAR" ? REGULAR  :
				type == "BANDITS" ? BANDITS  :
				type == "KINGDOM" ? KINGDOM  :
				type == "RAIDERS" ? RAIDERS  :
				type == "NORDS"   ? NORDS    :
				type == "PIRATES" ? PIRATES  :
				type == "CULTISTS"? CULTISTS :
				type == "WILDLIFE"? WILDLIFE :
				type == "EPIC"    ? EPIC     :
				type == "EVENT"   ? EVENT    : NONE;
	}
};

struct Initiative {
	enum EInitiative { NONE, FIRST, SECOND, THIRD, LAST };
	EInitiative init;
	Initiative() : init(NONE) {}
	operator EInitiative() {return init;}
	void operator=(EInitiative i2) {init = i2;}
	bool operator==(EInitiative const& i2) const { return init == i2; }
	std::string toString() {
		return 	init == FIRST  ? "FIRST"  :
				init == SECOND ? "SECOND" :
				init == THIRD  ? "THIRD"  :
				init == LAST   ? "LAST"   :
				init == NONE   ? "NONE"   : "INVALID";
	}
	bool checkSet(std::string const& str) {
		if(init != NONE) return false;
		init = 	str == "FIRST"  ? FIRST  :
				str == "SECOND" ? SECOND :
				str == "THIRD"  ? THIRD  :
				str == "LAST"   ? LAST   : NONE;
		return init != NONE;
	}
};

class Unit 
{
public:

	/* **************************************************************************************************** */

//	enum Initiative { I_NONE, I_FIRST, I_SECOND, I_THIRD, I_LAST };

	/* **************************************************************************************************** */

	Unit ();

	std::string         name_id,
	                    name;
	int                 _name_utf8_length;
	int                 hitpoints;
	int                 min_damage, max_damage;
	unsigned char       accuracy;
	Initiative          initiative;
	Enemy::Type         enemy_unit_type;   // only if computer unit
	Enemy				damage_bonus;      // bonus damage against computer units
	Skill				skills;
	int                 attack_id;
	int                 costs;

	/* **************************************************************************************************** */

	/*
	 * creates new unit with given name
	 *  - name_id  : string ID, must be unique, must not be a prefix of another unit
	 *  - error    : if an error occurs, e.g. 'name_id' is a prefix, then the error string is written here and NULL is returned
	 */
	static Unit* create(std::string const& name_id, std::string const& name, std::string& error);

	static Unit* get(std::string const& name_id, bool force_name_id=false);

	static const Unit* find(std::string const& name, std::string& error);

	static bool  set_name(std::string const& name_id, std::string const& name, std::string& error);

	static bool  has(std::string const& name_id);
};



#endif // UNITS_H_
